#pragma once

#include <iostream>
#include <pthread.h> 
#include <queue>
#include"lockGuard.hpp"
#include"task.hpp"

const int MAX_QUEUE_SIZE = 5;

template <class T>
class BlockingQueue
{
public:
    BlockingQueue(int num = MAX_QUEUE_SIZE)
        :_capacity(num)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_consumerCond, nullptr);
        pthread_cond_init(&_producerCond, nullptr);
    }
    ~BlockingQueue()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_consumerCond);
        pthread_cond_destroy(&_producerCond);
    }

    void push(const T& task)
    {
        // 1. 加锁
        lockGuard lock(&_mutex);
        // 2. 判断队列是否已满
        while(isFull())
        {
            // 3. 如果已满，就等待
            pthreadWait(_producerCond);
        }
        // 4. 如果不满，就将任务入队
        _queue.push(task);
        // 5. 唤醒消费者
        pthreadWakeup(_consumerCond);
        // 6. 解锁 -- lockGuard析构自动解锁
    }

    void pop(T* task)
    {
        // 1. 加锁
        lockGuard lock(&_mutex);
        // 2. 判断队列是否为空
        while(isEmpty())
        {
            // 3. 如果为空，就等待
            pthreadWait(_consumerCond);
        }
        // 4. 如果不为空，就将任务出队
        *task = _queue.front();
        _queue.pop();
        // 5. 唤醒生产者
        pthreadWakeup(_producerCond);
        // 6. 解锁 -- lockGuard析构自动解锁
    }

private:
    bool isEmpty()
    {
        return _queue.empty();
    }

    bool isFull()
    {
        return _queue.size() == _capacity;
    }

    void pthreadWait(pthread_cond_t& cond)
    {
        pthread_cond_wait(&cond, &_mutex);
    }

    void pthreadWakeup(pthread_cond_t& cond)
    {
        pthread_cond_signal(&cond);
    }
private:
    std::queue<T> _queue;
    int _capacity;
    pthread_mutex_t _mutex;
    pthread_cond_t _consumerCond;
    pthread_cond_t _producerCond;

};